import { IPoolable } from "../interfaces/IPoolable";

/**
 * 对象池
 */
export class Pool<T extends IPoolable> {
    /**
     * 正在使用中的对象
     */
    private __using: Array<T>;
    /**
     * 对象池
     */
    private __pool: Array<T>;
    /**
     * 对象构造函数
     */
    private __class: new () => T;
    /**
     * 对象池最大数量
     */
    private __maxCount: number | undefined;
    /**
     * 对象池内对象数量
     */
    private __countIndex: number = 0;

    constructor(type: new () => T, maxCount?: number) {
        this.__class = type;
        this.__using = [];
        this.__pool = [];
        this.__maxCount = maxCount;
    }

    /**
     * 分配一个对象
     * @returns 
     */
    alloc(): T {
        let result: T;
        if (this.__pool.length > 0) {
            result = this.__pool.pop() as T;
            this.__using.push(result);
        } else {
            result = new this.__class();
            this.__using.push(result);
            if (this.__maxCount != undefined) {
                this.__countIndex++;
                if (this.__countIndex > this.__maxCount) {
                    throw new Error("池内数量超出规定范围:" + this.__maxCount);
                }
            }
        }
        result.enable();
        return result;
    }

    /**
     * 回收一个所有对象
     */
    recycleAll(): void {
        while (this.__using.length > 0) {
            this.recycle(this.__using[0]);
        }
        this.__using.length = 0;
    }

    /**
     * 回收一个对象
     * @param v 
     */
    recycle(v: T): void {
        const index = this.__using.indexOf(v);
        if (index < 0) {
            throw new Error("组件不属于该对象池!");
        }
        this.__using.splice(index, 1);
        v.reset();
        this.__pool.push(v);
    }

    /**
     * 销毁所有对象
     */
    destroy(): void {
        for (let index = 0; index < this.__using.length; index++) {
            const element = <any>this.__using[index];
            element.destroy();
        }
        for (let index = 0; index < this.__pool.length; index++) {
            const element = <any>this.__pool[index];
            element.destroy();
        }
        this.__using.splice(0, this.__using.length);
        this.__using = null;
        this.__pool.splice(0, this.__pool.length);
        this.__pool = null;
    }

    /**
     * 获取当前池中正在使用的对象
     */
    get elements(): Array<T> {
        return this.__using;
    }

    /**
     * 获取当前池中所有对象的数量
     */
    get count(): number {
        return this.__countIndex;
    }
}